package com.se.invigilation.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.se.invigilation.dox.Invigilation;
import com.se.invigilation.dox.User;
import com.se.invigilation.dto.*;
import com.se.invigilation.exception.XException;
import com.se.invigilation.service.CollegeService;
import com.se.invigilation.service.CommonService;
import com.se.invigilation.service.DingtalkService;
import com.se.invigilation.service.SubjectService;
import com.se.invigilation.vo.RequestConstant;
import com.se.invigilation.vo.ResultVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;

@RestController
@RequestMapping("/api/")
@Slf4j
@RequiredArgsConstructor
public class CommonController {
    private final CommonService commonService;
    private final ObjectMapper objectMapper;
    private final CollegeService collegeService;
    private final SubjectService subjectService;
    private final DingtalkService dingtalkService;

    @PostMapping("passwords")
    public Mono<ResultVO> postPassword(@RequestBody User user,
                                       @RequestAttribute(RequestConstant.UID) String uid) {
        return commonService.updatePassword(uid, user.getPassword()).
                thenReturn(ResultVO.ok());
    }

    @GetMapping("users/{account}")
    public Mono<ResultVO> getUser(@PathVariable String account) {
        return commonService.getUser(account)
                .map(ResultVO::success);
    }

    // 获取指定全部用户的DING IDS。虽然是获取，但通过post传递参数较方便
    @PostMapping("invinotices/dingids")
    public Mono<ResultVO> postUserIds(@RequestBody List<String> ids) {
        return commonService.listUsersDingIds(ids).map(ResultVO::success);
    }

    // 发送取消监考通知，取消日历
    @PostMapping("cancelinvinotices/{inviid}")
    public Mono<ResultVO> deleteInvigilation(
            @RequestBody CancelNoticeDTO cNotice,
            @PathVariable String inviid) {
        Mono<Void> cancelNoticeM = commonService.sendCancelNotice(cNotice);
        Mono<Void> dingNoticeM = commonService.updateInviDingNotice(inviid, null);
        return Mono.when(cancelNoticeM, dingNoticeM).thenReturn(ResultVO.ok());
    }

    // 加载指定日期内全部监考
    @GetMapping("invis/date/{sdate}/{edate}")
    public Mono<ResultVO> getinvisDate(
            @PathVariable String sdate,
            @PathVariable String edate,
            @RequestAttribute(RequestConstant.ROLE) String role,
            @RequestAttribute(RequestConstant.DEPID) String depid,
            @RequestAttribute(RequestConstant.COLLID) String collid) {
        Mono<List<Invigilation>> invigilationsMono;
        if (User.COLLEGE_ADMIN.equals(role)) {
            invigilationsMono = collegeService.listInvisByDateByCollId(collid, sdate, edate);
        } else if (User.SUBJECT_ADMIN.equals(role)) {
            invigilationsMono = subjectService.listInvisByDateByDepId(depid, sdate, edate);
        } else {
            invigilationsMono = Mono.empty();
        }
        return invigilationsMono.map(ResultVO::success);
    }

    // 手动添加一个监考
    @PostMapping("invigilations")
    public Mono<ResultVO> postInvigilation(@RequestBody Invigilation invigilation,
                                           @RequestAttribute(RequestConstant.COLLID) String collid) {
        invigilation.setCollId(collid);
        return commonService.addInvigilation(invigilation)
                .thenReturn(ResultVO.ok());
    }

    // 发送钉钉监考通知，监考日程
    @PostMapping("assignnotices")
    public Mono<ResultVO> postAssignNotices(@RequestBody NoticeDTO notice) {
        return dingtalkService.sendNotice(notice.getDingNotice().getDingIds(), notice.getNoticeMessage())
                .then(Flux.fromIterable(notice.getDingNotice().getCalendars())
                        .flatMap(calendar -> {
                            // 创建日历
                            return dingtalkService.addCalander(calendar.getUnionId(),
                                            notice.getDate(),
                                            notice.getStime(),
                                            notice.getEtime(),
                                            notice.getNoticeMessage(),
                                            notice.getRemindMinutes())
                                    .flatMap(eventId -> {
                                        calendar.setEventId(eventId);
                                        return Mono.just(calendar);
                                    });
                        }).collectList()
                ).then(Mono.defer(() -> {
                    try {
                        var result = objectMapper.writeValueAsString(notice.getDingNotice());
                        return commonService.updateInviDingNotice(notice.getInviId(), result);
                    } catch (JsonProcessingException e) {
                        throw XException.builder()
                                .message(e.getMessage())
                                .build();
                    }
                }))
                .thenReturn(ResultVO.ok());
    }

    // 删除原监考详细信息；创建新监考详细信息
    @PostMapping("invidetails/{inviid}")
    public Mono<ResultVO> postInviDetails(@PathVariable String inviid,
                                          @RequestBody AssignUserDTO assignUser) {
        return commonService.addInvidetails(inviid, assignUser)
                .map(ResultVO::success);
    }

}
